#include "Kernel.h"

#include "Views/ViewManager.h"
#include "Views/GameView.h"
#include "Views/MenuView.h"

#include <glm/glm.hpp>

#include <libtcod/sys_opengl3.h>

#include <sstream>
#include <Windows.h>

KernelPtr Kernel::singleton;

KernelPtr Kernel::getSingleton()
{
	if(singleton == nullptr)
		singleton = std::make_shared<Kernel>();
	return singleton;
}

void Kernel::Shutdown()
{
	if(singleton)
	{
		long count = singleton.use_count();
		singleton.reset();
	}
}

Kernel::Kernel()
{
}

Kernel::~Kernel()
{
}

std::string Kernel::getGameModeString() const
{
	std::stringstream ss;
	ss << width << "x" << height << ":" << depth << "@" << refresh_rate;
	return ss.str();
}

std::string Kernel::getOpenGLVersionString() const
{
	std::stringstream ss;
	ss << opengl_major_version << "." << opengl_minor_version;
	return ss.str();
}

void Kernel::config(const std::string &resource_dir)
{
	this->resource_dir = resource_dir;
}

void Kernel::init(int argc, char** argv)
{
	TCODSystem::setInitAttribCallback(&GL3::Sys_Opengl3::TCOD_opengl_init_attributes);
	TCODSystem::setInitStateCallback(&GL3::Sys_Opengl3::TCOD_opengl_init_state);
	TCODSystem::setInitShadersCallback(&GL3::Sys_Opengl3::TCOD_opengl_init_shaders);
	TCODSystem::setRenderCallback(&GL3::Sys_Opengl3::TCOD_opengl_render);
	TCODSystem::setSwapCallback(&GL3::Sys_Opengl3::TCOD_opengl_swap);
	TCODSystem::setGetScreenCallback(&GL3::Sys_Opengl3::TCOD_opengl_get_screen);

	viewMgr = std::unique_ptr<Views::ViewManager>(new Views::ViewManager(resource_dir, "Trefall's Roguelike", glm::ivec2(90, 60), TCOD_LEFT));
	//TODO: Switch to load content in folder or something like that...
	viewMgr->add("MAIN_MENU.view");
	viewMgr->add("GAME.view");

	viewMgr->pushActive("MAIN_MENU");

	TCODMouse::showCursor(true);
}

void Kernel::run()
{
	running = true;
	while(TCODConsole::isWindowClosed() == false && running)
	{
		update(TCODSystem::getLastFrameLength());
		render();
		TCODConsole::flush();
		Sleep(0);
	}

	Kernel::Shutdown();
}

void Kernel::update(float dt)
{
	TCOD_event_t event = TCODSystem::checkForEvent(TCOD_EVENT_ANY,&key,&mouse);
	switch(event)
	{
	case TCOD_EVENT_KEY_PRESS:
		inputKeyDown(); break;
	case TCOD_EVENT_KEY_RELEASE:
		inputKeyUp(); break;
	case TCOD_EVENT_MOUSE_MOVE:
		motion(); break;
	case TCOD_EVENT_MOUSE_PRESS:
		mousePressed(); break;
	case TCOD_EVENT_MOUSE_RELEASE:
		mouseReleased(); break;
	};

	viewMgr->update(dt);
}

void Kernel::render()
{
	viewMgr->render();
}

void Kernel::reshape(int w, int h)
{
}

void Kernel::inputKeyDown()
{
	viewMgr->inputKeyDown(key, mouse);
}

void Kernel::inputKeyUp()
{
	viewMgr->inputKeyUp(key, mouse);
}

void Kernel::motion()
{
	viewMgr->motion(key, mouse);
}

void Kernel::mousePressed()
{
	viewMgr->mousePressed(key, mouse);
}

void Kernel::mouseReleased()
{
	viewMgr->mouseReleased(key, mouse);
}
